﻿#pragma once
#include "CGALDefine.h"
#include "RoadLineDesign.h"
#include "BasicObject.h"
#define USE_CGAL_TERRIAN
#define USE_CONSTRAINT_TRIANGLE

#ifdef USE_FADE25D_TERRIAN
#include <Fade_2D.h>
class RoadTerrian
{
public:
	typedef int ConstrainPolyonID;//<idGroup, 
public:
	int GetPntNum() const
	{
		return m_pTerrain->numberOfPoints();
	};

	int InsertConstrained(ConstrainPolyonID& idPolyon, const ZMVector<ZMPoint3D>& vConstrain);

	int RemoveAllConstrined();

	int RemoveConstrined(ConstrainPolyonID id, bool isNeedUpdate = true);

	void LoadData(QString strFileName);

	int GetHeight(const ZMReal& x, const ZMReal& y, ZMReal& z) const;

	void GetTriangleMeshData(MeshData& meshData);

	void UpdatePntAndTriData() {};
protected:
	map<GEOM_FADE25D::Triangle2*, int> GetTriangleDomains();
private:
	SharedPointer<GEOM_FADE25D::Fade_2D> m_pTerrain;
	ZMVector<GEOM_FADE25D::Zone2*> m_vContrainZone;
};
#endif


#ifdef USE_CGAL_TERRIAN

#include <CGAL/Constrained_Delaunay_triangulation_2.h>
#include <CGAL/Constrained_triangulation_plus_2.h>
#include <CGAL/Triangulation_face_base_with_info_2.h>
#include <CGAL/Polygon_with_holes_2.h>

#ifndef USE_CGAL_INTERSECTION
	#include "clipper.hpp"
#endif
class RoadTerrian
{
	struct FaceInfo2
	{
		FaceInfo2() {}
		int nesting_level;
		bool in_domain() {
			return nesting_level % 2 == 1;
		}
	};
	static const int m_IDContrianFrom = 5e+5;
	static const int m_IDContrianGroupNum = 1e+4;
	typedef KCGALWithInfo													  K;
	typedef CGAL::Polygon_2<K>                                                Polygon_2;
	typedef CGAL::Polygon_with_holes_2<K>                                     Polygon_with_holes_2;
	typedef CGAL::Exact_intersections_tag                                     Itag;
	typedef CGAL::Triangulation_vertex_base_2<K>                      Vb;
	typedef CGAL::Triangulation_face_base_with_info_2<FaceInfo2, K>    Fbb;
	typedef CGAL::Constrained_triangulation_face_base_2<K, Fbb>        Fb;
	typedef CGAL::Triangulation_data_structure_2<Vb, Fb>               TDS;
	typedef CGAL::Constrained_Delaunay_triangulation_2<K, TDS, Itag>  CDT;
	typedef CGAL::Constrained_triangulation_plus_2<CDT>                       CDTP;
	typedef CDTP::Point                                                       Point;

#ifdef USE_CONSTRAINT_TRIANGLE
	struct suIdPolyon
	{
		int m_idRoad;
		int m_inxContrain;
		bool operator<(const suIdPolyon& id) const
		{
			bool ret = false;
			if (m_idRoad < id.m_idRoad) ret = true;
			if (m_idRoad == id.m_idRoad && m_inxContrain < id.m_inxContrain) ret = true;
			return ret;
		}
		bool operator==(const suIdPolyon& id) const
		{
			if (m_idRoad == id.m_idRoad && m_inxContrain == id.m_inxContrain)
			{
				return true;
			}
			return false;
		}
	};

	struct suConstrainPolyInfo
	{
		Polygon_2 m_poly;
		int m_idPolyUnit;//对应的由多个多边形合并而成的大多边形id
		suIdPolyon m_idConstrain;
	};

	struct suUnitPolyInfo
	{
		int m_idPolyUnit;
		ZMVector<CDTP::Constraint_id> m_idConstrain;////有多个多边形构成的大多边形，由于各种复杂情况，多个多边形合并不一定是一个多边形，所以不一定只有一个限制id
		list<suIdPolyon> m_vInxPolyInfo;//合并的多个多边形id
	};
#endif
public:
#ifdef USE_CONSTRAINT_TRIANGLE
	typedef suIdPolyon ConstrainPolyonID;//<idGroup, 
#else 
	typedef int ConstrainPolyonID;//<idGroup, 
#endif

	RoadTerrian();

	~RoadTerrian();

	int GetPntNum() const 
	{
		return m_Triangle.number_of_vertices();
	};

#ifdef USE_CONSTRAINT_TRIANGLE
	int InsertConstrained(ConstrainPolyonID& idPolyon, int inxRoad, const ZMVector<ZMPoint3D>& vConstrain, bool isNeedUpdate = true);
#else 
	int InsertConstrained(ConstrainPolyonID& idPolyon, const ZMVector<ZMPoint3D>& vConstrain)
	{
		ZMVector<Point>  vPnt = ToCGALPntData(vConstrain);
		if (CGAL::squared_distance(vPnt[0], vPnt[vPnt.size() - 1]) < 0.01*0.01)
		{
			vPnt.pop_back();
		}
		Polygon_2 poly;
		for (int i=0; i< vPnt.size(); ++i)
		{
			if (i > 0)
			{
				if (CGAL::squared_distance(CGALPoint2(vPnt[i].x(), vPnt[i].y()), CGALPoint2(vPnt[i -1].x(), vPnt[i -1].y())) > 0.01*0.01)
				{
					poly.push_back(vPnt[i]);
				}
			}
			else
			{
				poly.push_back(vPnt[i]);
			}
		}
		if (!poly.is_simple())
		{
			ZMVector<Polygon_2> vPolyon = SimplePolygon(poly);
			m_vContrainPoly.insert(m_vContrainPoly.end(), vPolyon.begin(), vPolyon.end());
		}
		else
		{
			m_vContrainPoly.push_back(poly);
		}
		idPolyon = m_vContrainPoly.size() - 1;
		return 0;
	}
#endif

	void UpdatePntAndTriData()
	{
#ifdef USE_CONSTRAINT_TRIANGLE
		UpdatePntInx();
		UpdateTriangleDomains();
#endif
	}

	int RemoveAllConstrined();

	int RemoveConstrined(ConstrainPolyonID id, bool isNeedUpdate = true);

	void ClearTriData()
	{
		m_Triangle.clear();
#ifdef USE_CONSTRAINT_TRIANGLE
		m_mapUnitAndID.clear();
		m_vConstrainPolyGroup.clear();
#else
		m_vContrainPoly.clear();
#endif
		m_FaceCatch = CDTP::Face_handle();
	}

	void ClearALLData()
	{
		ClearTriData();
	}

	void LoadData(QString strFileName);

	void LoadDataTemp(QString strFileName, const ZMVector<ZMReal>& vMile, const ZMVector<ZMPoint3D>& vPnt, const ZMVector<ZMReal>& vAngle, PRoadLineDesign pRoadLine);

	void SavePntData(QString strFileName) ;

	void Save(QString strFileName, int iSaveType = 0) ;

	void Load(QString strFileName, int iSaveType = 0);

	int GetHeight(const ZMReal& x, const ZMReal& y, ZMReal& z) const;

	void GetTriangleMeshData(MeshData& meshData);

	void WriteDataToCAD(ZMString strFileName, const ZMPoint3D& pnt, ZMReal fDis = 400);

protected:
#ifndef USE_CONSTRAINT_TRIANGLE
	void UpdateMeshData(ZMVector<ZMPoint3D>&vPnt, ZMVector<int>& vInx);
#endif

	bool IsValidPolyon(ZMReal fScale, const ClipperLib::Path& polyon);

	void WritePolyon(const Polygon_2& polyon, CFileSaveData& fp);


	void GetOriginMeshData(ZMVector<CGALPoint>&vPnt, ZMVector<int>& vInx);

#ifndef USE_CONSTRAINT_TRIANGLE
	void UpdateTreeData();
#endif
#ifdef USE_CONSTRAINT_TRIANGLE
	int RemoveConstrined(int inx, bool isNeedUpdate = true);
#endif

	void WritePoint(CSaveData& fp, const Point& pnt)
	{
		int inx = pnt.Index();
		ZMReal x = pnt.x(), y = pnt.y(),z=pnt.z();

		fp.Write(inx);
		fp.Write(x);
		fp.Write(y);
		fp.Write(z);
	}
#ifdef USE_DOUBLE
	void ReadPoint(CLoadData& fp, Point& pnt)
	{
		int inx;
		ZMReal x, y, z;
		fp.Read(inx);
		fp.Read(x);
		fp.Read(y);
		fp.Read(z);
		pnt = Point(x, y);
		pnt.Index() = inx;
		pnt.z() = z;
	}
#else
	void ReadPoint(CLoadData& fp, Point& pnt)
	{
		int inx;
		double x, y, z;
		fp.Read(inx);
		fp.Read(x);
		fp.Read(y);
		fp.Read(z);
		pnt = Point(x - XMIN, y-YMIN);
		pnt.Index() = inx;
		pnt.z() = z;
	}
#endif
	
	
	ZMVector<Point> ToCGALPntData(const ZMVector<ZMPoint3D>& vPnt) const
	{
		ZMVector<Point> vRet;
		vRet.resize(vPnt.size());
		for (int j = 0; j < vPnt.size(); ++j)
		{
			vRet[j] = Point(vPnt[j][0], vPnt[j][1]);
			vRet[j].Index() = 1;
			vRet[j].z() = vPnt[j][2];
		}
		return vRet;
	}

	//int ContructTriangle();

	void SaveAscii(CFileSaveData& fp) ;

	void SaveBinaray(CSaveData& fp);

	void LoadBinaray(CLoadData& fp);

	void LoadAscii(CFileLoadData& fp);
	
	void UpdateTriangleDomains();

	void mark_domains(CDTP::Face_handle start, int index, std::list<CDTP::Edge>& border);

	void UpdatePntInx();

#ifdef DEBUG
	void SimpleData();
#endif

#ifdef USE_CONSTRAINT_TRIANGLE
	ConstrainPolyonID AddConstrainPoly(int idRoad, const Polygon_2& vConstrain);
	
	suConstrainPolyInfo& GetPolyInfo(const ConstrainPolyonID& id)
	{
		map<int, ZMVector<suConstrainPolyInfo>>::iterator pos = m_vConstrainPolyGroup.find(id.m_idRoad);
		return pos->second[id.m_inxContrain];
	}

	ZMVector<ConstrainPolyonID> FindRelationPolyonID(const ConstrainPolyonID& id)
	{
		const list<suIdPolyon> & lsInfo = m_mapUnitAndID.find(GetPolyInfo(id).m_idPolyUnit)->second.m_vInxPolyInfo;
		ZMVector<ConstrainPolyonID> ret;
		ret.insert(ret.end(), lsInfo.begin(), lsInfo.end());
		
		return ret;
	}
#endif

	bool DoIntersection(const Polygon_2& poly1, const Polygon_2& poly2);

	ZMVector<Polygon_2> IntersectionUnit(const Polygon_2& poly, const ZMVector<Polygon_2 >& vPoly);

	ZMVector<Polygon_2> SimplePolygon(const Polygon_2& poly, bool bUseNewData = false);

#ifndef USE_CGAL_INTERSECTION
	ClipperLib::Path ToClipperPath(const Polygon_2& poly, ZMReal fScale = 1e+3, ZMReal xMin = XMIN, ZMReal yMin = YMIN);

	CGALPoint IntPntToCGALPnt(const ClipperLib::IntPoint& pnt, ZMReal fScale = 1e+3, ZMReal xMin = XMIN, ZMReal yMin = YMIN);

	Polygon_2 ToPolyon(const ClipperLib::Path& poly, ZMReal fScale = 1e+3, ZMReal xMin = XMIN, ZMReal yMin = YMIN);

	int ToClipperPaths(ClipperLib::Paths& vPoly, const ZMVector<CGALPoint>&vPnt, const  ZMVector<int>& vInx, ZMReal fScale = 1e+3, ZMReal xMin = XMIN, ZMReal yMin = YMIN);
#endif
private:
	//ZMVector<ZMPoint3D> m_vPntTemp;
	//ZMVector <ZMVector<Point>> m_vContrainPnt;
	//ZMVector<Point> m_vPnt;
	CDTP m_Triangle;

#ifdef USE_CONSTRAINT_TRIANGLE
	map<int, suUnitPolyInfo> m_mapUnitAndID;

	map<int, ZMVector<suConstrainPolyInfo>> m_vConstrainPolyGroup;// int:相互之间不需要合并的多边形组id，  多边形info，根据组id和info ID可以确定一个多边形
	static int m_idUnitPolyInxMax;
#else
	ZMVector<Polygon_2> m_vContrainPoly;
	PTreeTri	m_pTree;
	ZMVector<CGALTriangle> m_vTri;
#endif

	CDTP::Face_handle m_FaceCatch;

};
#endif
typedef SharedPointer<RoadTerrian> PRoadTerrian;
